#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/arm-smccc.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Test");
MODULE_DESCRIPTION("ARM SMC Test Module using kernel's arm_smccc_smc");

// 设备节点相关（用于用户态触发测试）
#define SMC_TEST_DEV "smc_test"
static int major;

// ARM标准SMC功能号（参考ARM DEN 0028）
#define SMC_STD_VERSION 0x80000000 // 查询安全监控器版本
#define SMC_STD_DISCOVER_FEATURES 0x80000001 // 发现支持的功能
#define SMC_STD_GET_SOC_ID 0x80000003 // 获取SOC ID（部分设备支持）

// 测试：查询安全监控器版本
static void test_smc_version(void)
{
	struct arm_smccc_res res;

	pr_info("\n=== Testing SMC_STD_VERSION (0x%x) ===", SMC_STD_VERSION);
	// 调用内核SMC接口：功能号0x80000000，无参数
	arm_smccc_smc(SMC_STD_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);

	if (res.a0 == 0xFFFFFFFF) {
		pr_info("Standard SMC version not supported\n");
		return;
	}

	// 解析版本号（格式：主版本<<16 | 次版本）
	u32 major = (res.a0 >> 16) & 0xFFFF;
	u32 minor = res.a0 & 0xFFFF;
	pr_info("Secure Monitor Version: v%d.%d\n", major, minor);
	pr_info("Additional info: a1=0x%lx, a2=0x%lx\n", res.a1, res.a2);
}

// 测试：检查TrustZone特性
static void test_smc_trustzone(void)
{
	struct arm_smccc_res res;
	// 参数x1=0：查询TrustZone支持特性
	pr_info("\n=== Testing SMC_STD_DISCOVER_FEATURES (0x%x) ===\n", SMC_STD_DISCOVER_FEATURES);
	arm_smccc_smc(SMC_STD_DISCOVER_FEATURES, 0, 0, 0, 0, 0, 0, 0, &res);

	// 结果解析（0表示支持，a1返回特性详情）
	if (res.a0 == 0) {
		pr_info("TrustZone supported: Yes\n");
		pr_info("Feature flags: 0x%lx\n", res.a1);
	} else {
		pr_info("TrustZone supported: No (error: 0x%lx)\n", res.a0);
	}
}

// 设备节点读操作（用户态触发测试）
static ssize_t smc_test_read(struct file *file, char __user *buf, size_t len, loff_t *off)
{
	test_smc_version();
	test_smc_trustzone();
	return 0;
}

// 文件操作结构体
static const struct file_operations smc_test_fops = {
	.read = smc_test_read,
};

// 模块加载函数
static int __init smc_test_init(void)
{
	// 注册字符设备
	major = register_chrdev(0, SMC_TEST_DEV, &smc_test_fops);
	if (major < 0) {
		printk(KERN_ERR "Failed to register device");
		return major;
	}
	pr_info("SMC test module loaded. Major: %d", major);
	pr_info("Run 'mknod /dev/%s c %d 0' to create device node", SMC_TEST_DEV, major);
	pr_info("Read /dev/%s to trigger SMC tests\n", SMC_TEST_DEV);
	return 0;
}

// 模块卸载函数
static void __exit smc_test_exit(void)
{
	unregister_chrdev(major, SMC_TEST_DEV);
	pr_info("SMC test module unloaded\n");
}

module_init(smc_test_init);
module_exit(smc_test_exit);
